import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';

interface NumberSquareProps {
    $defaultDisplay: boolean;
}

const NumberSquare = styled.span<NumberSquareProps>`
  display: inline-block;
  width: 2.125rem;
  height: 2.125rem;
  background-color: rgba(254, 156, 14, 0.24);
  color: #FE9C0E;
  margin-right: 5px;
  text-align: center;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 2.125rem;
  border-radius: 1.5625rem;
`;

interface NumberCounterProps {
    float?: {
        fix: number;
    }
    startValue: number;
    endValue: number;
    duration?: number;
    interval?: number; // animation interval frame, default is 1
    defaultDigitCount?: number;
    className?: string;
    numberClassName?: string;
    willunmount?: (value: number) => void;
    onEnd?: () => void;
}

const NumberCounter: React.FC<NumberCounterProps> = ({
    willunmount,
    onEnd,
    className,
    float,
    numberClassName,
    startValue,
    endValue,
    interval = 1,
    duration = 2000,
    defaultDigitCount = 4,
}) => {
    const [currentValue, setCurrentValue] = useState(startValue);
    const [digits, setDigits] = useState<string[]>(Array.from({ length: defaultDigitCount }, () => '0'));

    const ref = useRef(currentValue)
    useEffect(() => {
        ref.current = currentValue
    }, [currentValue])

    useEffect(() => {
        let startTimestamp: number;
        let animationFrameId: number;

        const cancelAnimation = () => {
            // Cleanup: Stop the animation when the component unmounts
            if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
            }
        }

        const fixCount = float?.fix || 0
        const formatValue = (value: number) => {
            if (fixCount) {
                return Number(value.toFixed(fixCount))
            }
            return Math.floor(value)
        }
        let timer: NodeJS.Timeout

        const startAnimation = (timestamp: number) => {
            clearTimeout(timer)
            if (!startTimestamp) startTimestamp = timestamp;
            const progress = Math.min((timestamp - startTimestamp) / duration, 1);
            const newValue = formatValue(progress * (endValue - startValue) + startValue)
            setCurrentValue(newValue);

            const func = fixCount ? 'padEnd' : 'padStart'
            const newDigits = Array.from(String(newValue)[func](defaultDigitCount, '0'));
            setDigits(newDigits);

            if (progress < 1) {
                if (interval > 1) {
                    timer = setTimeout(() => {
                        animationFrameId = requestAnimationFrame(startAnimation);
                    }, interval * 16);
                } else {
                    animationFrameId = requestAnimationFrame(startAnimation);
                }

            } else {
                onEnd?.()
                cancelAnimation();
                clearTimeout(timer)
            }
        };

        animationFrameId = requestAnimationFrame(startAnimation);

        return () => {
            cancelAnimation()
            clearTimeout(timer)
        };
    }, [startValue, endValue, duration, defaultDigitCount, onEnd, float?.fix, interval]);


    useEffect(() => {
        return () => {
            willunmount?.(ref.current)
            // onEnd?.(ref.current, true)
        }
    }, [willunmount, onEnd])

    const numberSquares = digits.map((digit, index) => (
        <NumberSquare
            className={numberClassName}
            key={index}
            $defaultDisplay={index < defaultDigitCount - digits.length}
        >
            {digit}
        </NumberSquare>
    ));

    return <div className={className}>{numberSquares}</div>;
};

export default NumberCounter;
